UI 系统

UI 系统

Godot 的 UI 系统基于 Control 节点,使用锚点和边距进行布局。

Control 节点基础

所有 UI 节点都继承自 Control

基本属性

extends Control

# 位置和大小
position = Vector2(100, 100)
size = Vector2(200, 50)

# 锚点(控制相对位置)
anchors_preset = PRESET_CENTER

# 边距
offset_left = 0
offset_right = 100
offset_top = 0
offset_bottom = 50

常用 UI 节点

Label (标签)

extends Label

func _ready() -> void:
    text = "Hello, World!"
    horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
    vertical_alignment = VERTICAL_ALIGNMENT_CENTER
    font_size = 24

Button (按钮)

extends Button

func _ready() -> void:
    text = "Click Me"

func _pressed() -> void:
    print("Button pressed!")

LineEdit (文本输入框)

extends LineEdit

signal text_submitted(new_text: String)

func _ready() -> void:
    placeholder_text = "Enter your name..."

func _on_text_submitted(new_text: String) -> void:
    print("Entered: ", new_text)
    text_submitted.emit(new_text)

ProgressBar (进度条)

extends ProgressBar

var current_value: float = 0.0
var max_value: float = 100.0

func update_progress(value: float) -> void:
    current_value = clamp(value, 0, max_value)
    value = (current_value / max_value) * 100

TextureRect (图像显示)

extends TextureRect

func _ready() -> void:
    texture = preload("res://images/icon.png")
    expand_mode = TextureRect.EXPAND_FIT_WIDTH_PROPORTIONAL

CheckBox (复选框)

extends CheckBox

signal toggled(is_checked: bool)

func _toggled(button_pressed: bool) -> void:
    print("Check box is: ", button_pressed)

布局容器

VBoxContainer (垂直布局)

extends VBoxContainer

func _ready() -> void:
    separation = 10  # 子元素间距
    alignment = ALIGNMENT_CENTER

HBoxContainer (水平布局)

extends HBoxContainer

func _ready() -> void:
    separation = 10
    alignment = ALIGNMENT_CENTER

GridContainer (网格布局)

extends GridContainer

func _ready() -> void:
    columns = 3
    # 按行添加子节点,会自动换行

MarginContainer (边距容器)

extends MarginContainer

func _ready() -> void:
    add_theme_constant_override("margin_left", 20)
    add_theme_constant_override("margin_right", 20)
    add_theme_constant_override("margin_top", 10)
    add_theme_constant_override("margin_bottom", 10)

CenterContainer (居中容器)

extends CenterContainer

func _ready() -> void:
    # 子元素自动居中

锚点系统

锚点控制 UI 元素相对于父容器的位置。

锚点预设

# 全屏填充
anchors_preset = PRESET_FULL_RECT

# 左上角
anchors_preset = PRESET_TOP_LEFT

# 居中
anchors_preset = PRESET_CENTER

# 左居中
anchors_preset = PRESET_CENTER_LEFT

# 底部全宽
anchors_preset = PRESET_BOTTOM_WIDE

UI 主题

使用内置主题

extends Control

func _ready() -> void:
    # 使用默认主题
    theme = Theme.new()

创建自定义主题

extends Control

@export var custom_theme: Theme

func _ready() -> void:
    theme = custom_theme

UI 与 3D 游戏结合

HUD (Heads-Up Display)

extends Control

@onready var health_bar = $HealthBar
@onready var score_label = $ScoreLabel

func update_health(current: int, max_value: int) -> void:
    health_bar.value = (float(current) / max_value) * 100

func update_score(score: int) -> void:
    score_label.text = "Score: " + str(score)

将 UI 覆盖在 3D 场景上

# Main 节点结构
# - World3D (Node3D)
#   - Camera3D
# - UI (Control) - 添加为同级,设置为 top level

对话系统示例

extends Control

@onready var dialog_label = $DialogBox/Label
@onready var continue_button = $DialogBox/Button

var dialogues: Array[String] = [
    "Welcome to the game!",
    "Use WASD to move.",
    "Press Space to jump."
]
var current_index: int = 0

func start_dialogue() -> void:
    visible = true
    show_dialogue()

func show_dialogue() -> void:
    if current_index < dialogues.size():
        dialog_label.text = dialogues[current_index]
    else:
        end_dialogue()

func _on_continue_button_pressed() -> void:
    current_index += 1
    show_dialogue()

func end_dialogue() -> void:
    visible = false

UI 动画

使用 Tween 缓动

extends Control

var tween: Tween

func fade_in() -> void:
    tween = create_tween()
    tween.tween_property(self, "modulate:a", 1.0, 0.5)

func fade_out() -> void:
    tween = create_tween()
    tween.tween_property(self, "modulate:a", 0.0, 0.5)

响应式设计

extends Control

func _ready() -> void:
    # 根据屏幕大小调整
    var screen_size = get_viewport_rect().size
    if screen_size.x < 800:
        scale_ui_for_mobile()

func scale_ui_for_mobile() -> void:
    $HealthBar.scale = Vector2(0.8, 0.8)
    $ScoreLabel.add_theme_font_size_override("font_size", 20)

鼠标光标

extends Control

func _ready() -> void:
    # 隐藏默认光标
    Input.set_mouse_mode(Input.MOUSE_MODE_HIDDEN)

    # 显示自定义光标
    Input.set_custom_mouse_cursor(preload("res://cursors/custom.png"))

虚拟摇杆(移动端)

extends Control

var touch_start: Vector2
var is_dragging: bool = false

signal joystick_moved(direction: Vector2)

func _input(event: InputEvent) -> void:
    if event is InputEventScreenTouch:
        if event.pressed:
            touch_start = event.position
            is_dragging = true
        else:
            is_dragging = false
            joystick_moved.emit(Vector2.ZERO)

    elif event is InputEventScreenDrag and is_dragging:
        var direction = (event.position - touch_start).normalized()
        joystick_moved.emit(direction)